package com.powergisol.gis.controller;

import cn.hutool.http.HttpUtil;
import com.powergisol.gis.service.ChangeMapService;
import com.powergisol.gis.service.IFileService;
import com.powergisol.gis.service.ProgressService;
import com.powergisol.gis.service.ServiceUploadService;
import com.powergisol.gis.util.*;
import com.powergisol.gis.vo.TabServiceVo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.google.code.kaptcha.Producer;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.File;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;


@RestController
@Api(description = "服务上传管理" ,value = "服务上传管理")
public class ServiceUploadController {
    private static Logger logger = LoggerFactory.getLogger(ServiceUploadController.class);

    @Autowired
    private ServiceUploadService serviceUploadService;

    @Autowired
    private IFileService fileService;

    @Autowired
    private RedisTemplate redisTemplate;
    @Value("${collectionName}")
    private String collectionName;
//    @Value("${file-url}")
//    private String fileUrl;

    @Value("${expira_time}")
    private Integer expiraTime;
    @Autowired
    private ChangeMapService changeMapService;
    @Autowired
    private Producer producer;

    @Autowired
    private ProgressService progressService;

    @ApiOperation("生成登陆验证码")
    @GetMapping("/producer/getCaptcha")
    public void getCode(HttpServletResponse response, HttpServletRequest request) throws Exception {
        response.setHeader("Cache-Control", "no-store, no-cache");
        response.setContentType("image/jpeg");
        //生成文字验证码
        String text = producer.createText();
        HttpSession session = request.getSession();
        session.setAttribute("imageCode",text);
        //生成图片验证码
        BufferedImage image = producer.createImage(text);
        ServletOutputStream out = response.getOutputStream();
        ImageIO.write(image, "jpg", out);
    }
    /**
     * 验证验证码
     *
     * @param code
     */
    @GetMapping("checkCaptcha")
    public Result checkCaptcha(String code,HttpServletRequest request) {
        try {
            HttpSession session = request.getSession();
            String kaptcha = (String)session.getAttribute("imageCode");
            if(null == kaptcha){
                return new Result().failure(-1,"请重新获取验证码");
            }
            if(null == code){
                return new Result().failure(-1,"验证码不能为空");
            }
            if(!kaptcha.equalsIgnoreCase(code)){
                return new Result().failure(-1,"验证码错误");
            }
        } catch (Exception e) {
            return new Result().failure(-1, e.getMessage());
        }
        return new Result().success();
    }

    @PostMapping("getFileUrl")
    @ApiOperation(value = "获取file路径", notes = "获取file路径")
    @ApiImplicitParams({
            @ApiImplicitParam(dataType = "String", name = "uuid", value = "uuid", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "Integer", name = "serviceType", value = "服务类型", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "changeType", value = "转换类型", defaultValue = "0", required = true, paramType = "query")
    })
    public Result getFileUrl(String uuid,Integer serviceType,String changeType) {
        Result result = new Result();
        if(1 != serviceType && 4 != serviceType && !(3==serviceType && ("terrain").equals(changeType))){//tif和shp不会转换跳过
            try {
                //文件转换json文件可能未生成，休眠30秒再读取
                TimeUnit.SECONDS.sleep(10);//秒
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //5、读取转换后文件
        String out = (String)redisTemplate.opsForValue().get(uuid+"Out");
        String in = (String)redisTemplate.opsForValue().get(uuid+"In");
        switch (serviceType){
           //注：shp文件获取点线面的样式需要修改
            case 6:
                if("pld".equals(changeType)){
                    out = out+ in.substring(in.lastIndexOf(File.separator),in.length())+File.separator+"model.json";
                }else if("b3dm".equals(changeType)){
                    out = out+File.separator+"tileset.json";
                }
                break;
            case 3:
                if("terrain".equals(changeType)){
                    out = out+File.separator+"layer.json";
                    break;
                }
                break;
        }
        //logger.info(uuid+"的文件路径：{}",out);
        //相应路径按全路径保存至数据库，后期删除盘中文件也可从数据库中读出相应的文件
        //主要用于获取属性 （tif和shp文件除外）
//        if(4 != serviceType && 1 != serviceType && !(3==serviceType && ("terrain").equals(changeType)) ){
//            File file = new File(out);
//            String name = file.getName();
//            String suffix = name.substring(name.lastIndexOf(".") + 1);
//            List<File> fileList = new ArrayList<>();
//            fileList.add(file);
//            fileService.importFilesToFs(file,uuid+file.getAbsolutePath(),suffix,uuid);
//        }
        if(4 != serviceType){
            File file = new File(out);
            String name = file.getName();
            String suffix = name.substring(name.lastIndexOf(".") + 1);
            List<File> fileList = new ArrayList<>();
            fileList.add(file);
            fileService.importFilesToFs(file,uuid+file.getAbsolutePath(),suffix,uuid);
        }
        Map<String,Object> map = new HashMap<>();
        map.put("fileUrl",out);
        map.put("originUrl", in);
        result.setData(map);
        return result;
    }

    /**
     * 转换后保存至数据库
     */
    @PostMapping("saveFileToDB")
    @ApiOperation(value = "转换后保存至数据库", notes = "转换后保存至数据库")
    @ApiImplicitParams({
            @ApiImplicitParam(dataType = "String", name = "uuid", value = "文件", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "name", value = "服务名称", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "Integer", name = "serviceType", value = "服务类型", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "changeType", value = "转换类型", defaultValue = "0", required = true, paramType = "query")
    })
    public Result saveFileToDB(String uuid,String name,Integer serviceType,String changeType) {
        Result result = new Result();
        //5、读取转换后文件
        String out = (String)redisTemplate.opsForValue().get(uuid+"Out");
        //logger.info("{}转换后保存入库输出文件：{}",name,out);
        Map<String,Object> resultMap = null;
        switch (serviceType){
            case 3:
                try {
                    //文件转换json文件可能未生成，休眠30秒再读取
                    TimeUnit.SECONDS.sleep(30);//秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                result = FileList.fileRead(out,"json");
                out = out+File.separator+"layer.json";
                resultMap = (Map<String,Object>)result.getData();
                break;
            case 6:
                try {
                    //文件转换json文件可能未生成，休眠30秒再读取
                    TimeUnit.SECONDS.sleep(30);//秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if("pld".equals(changeType)){
                    String in = (String)redisTemplate.opsForValue().get(uuid+"In");
                    out = out+ in.substring(in.lastIndexOf(File.separator),in.length());
                    result = FileList.fileRead(out,"json");
                    out = out + File.separator+"model.json";
                }else if("b3dm".equals(changeType)){
                    result = FileList.fileRead(out,"json");
                    out = out+File.separator+"tileset.json";
                }
                resultMap = (Map<String,Object>)result.getData();
                break;
            case 7:
                try {
                    //文件转换json文件可能未生成，休眠30秒再读取
                    TimeUnit.SECONDS.sleep(30);//秒
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
               // File file = new File(out);
                result = FileList.fileRead(out.substring(0,out.lastIndexOf(File.separator)),"glb");
               // out = out.substring(0, out.lastIndexOf(File.separator));
                resultMap = (Map<String,Object>)result.getData();
                break;
        }
        if(null!=resultMap && null != resultMap.get("listFile")){
           // logger.info("{}转换后保存入库开始",name);
            List<File> changeList = ( List<File>)resultMap.get("listFile");
            redisTemplate.opsForValue().set(uuid+"TotalSize",changeList.size(),expiraTime,TimeUnit.HOURS);  //6、保存入库
            serviceUploadService.saveFileToDb(changeList,uuid,name,out.replace("/",File.separator));
            resultMap.remove("listFile");
        }
        return result;
    }


    /**
     * 数据上传
     * @param file 数据上传
     * @return
     */
    @PostMapping("fileUploadData")
    @ApiOperation(value = "数据上传", notes = "数据上传")
    @ApiImplicitParams({
            @ApiImplicitParam(dataType = "MultipartFile", name = "file", value = "文件", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "Integer", name = "serviceType", value = "服务类型", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "assinSuffixName", value = "后缀名", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "codeType", value = "字符编码", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "changeType", value = "osgb指定转换类型（表b3dm、lob、pld）", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "isCut", value = "是否切片(1是)", defaultValue = "0", required = true, paramType = "query")
    })
    public Result fileUploadData(MultipartFile file, TabServiceVo vo) {
        String userDir = System.getProperty("user.dir");
        userDir = userDir.substring(0,userDir.lastIndexOf(File.separator));
        Result result = FileUpload.fileUpload(file,userDir+File.separator+"serviceData",vo);
        Map<String,Object> map = (Map<String,Object>)result.getData();
        serviceUploadService.unZiphThread(map,vo);
        return result;
    }

    @PostMapping("getFileProgress")
    @ApiOperation(value = "获取上传进度", notes = "获取上传进度")
    @ApiImplicitParams({
            @ApiImplicitParam(dataType = "String", name = "uuid", value = "上传位移标识", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "Integer", name = "serviceType", value = "服务类型", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "changeType", value = "转换类型", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "startLevel", value = "转换层数", defaultValue = "0", required = true, paramType = "query")
    })
    public Result getFileProgress(String uuid,Integer serviceType,String changeType,String startLevel) {
        Result result = new Result();
        Map<String,Object> map = new HashMap<>();
        //解压进度
        BigDecimal unzipProgress = null != redisTemplate.opsForValue().get(uuid+"UnzipProgress")?new BigDecimal(redisTemplate.opsForValue().get(uuid + "UnzipProgress").toString()):BigDecimal.ZERO;
        map.put("unzipProgress",unzipProgress);

        //总的条数
        BigDecimal totalSize = null!=redisTemplate.opsForValue().get(uuid + "TotalSize")?new BigDecimal(redisTemplate.opsForValue().get(uuid + "TotalSize").toString()):BigDecimal.ZERO;
        //转换进度
        Double changeProgress = null!=redisTemplate.opsForValue().get(uuid + "ExchangeProgress")?Double.valueOf(redisTemplate.opsForValue().get(uuid + "ExchangeProgress").toString()):0d;
        //转换为1或-1则无需调用转换速度接口
        if(changeProgress !=1 && changeProgress != -1){
            switch (serviceType){
                case 6:
                    if(redisTemplate.hasKey(uuid+"In")&&redisTemplate.hasKey(uuid+"Out")){
                        String in = (String)redisTemplate.opsForValue().get(uuid+"In");
                        String out = (String)redisTemplate.opsForValue().get(uuid+"Out");
                        if("pld".equals(changeType)){
                            out = out+ in.substring(in.lastIndexOf(File.separator),in.length());
                           // logger.info("Osgb2Pld转换输入in={},out={}",in,out);
                            try{
                                changeProgress = progressService.osgb2Pld(uuid,in,out);
                               // changeProgress = changeMapService.osgb2Pld(in,out);
                               // logger.info("Osgb2Pld转换进度={}",changeProgress);
                            }catch (Exception e){
                                result.setCode(405);
                            }
                        }else if("b3dm".equals(changeType)){
                            //logger.info("Osgb2b3dm转换输入in={},out={}",in,out);
                            try{
                               // changeProgress = changeMapService.progressOsgb2b3dm(in,out);
                                changeProgress = progressService.osgb2b3dm(uuid,in,out);
                            }catch (Exception e){
                                result.setCode(405);
                            }
                        }
                    }
                    break;
                case 7:
                    if(redisTemplate.hasKey(uuid+"In")&&redisTemplate.hasKey(uuid+"Out")){
                        String in = (String)redisTemplate.opsForValue().get(uuid+"In");
                        String out = (String)redisTemplate.opsForValue().get(uuid+"Out");
                        try{
                            changeProgress = progressService.objToGltf(uuid,in.substring(0,in.lastIndexOf(File.separator)),out.substring(0,out.lastIndexOf(File.separator)));
//                            changeProgress = changeMapService.
//                                    progressObjToGltf(in.substring(0,in.lastIndexOf(File.separator)),out.substring(0,out.lastIndexOf(File.separator)));
                        }catch (Exception e){
                            result.setCode(405);
                        }
                    }
                    break;
                case 3:
                    if("terrain".equals(changeType)){
                        if(redisTemplate.hasKey(uuid+"Out")){
                            String out = (String)redisTemplate.opsForValue().get(uuid+"Out");
                            //logger.info("Tif2terrain转换输出out={}",out);
                            try{
                                //changeProgress = progressService.tif2terrain(uuid,startLevel,out);
                                changeProgress = changeMapService.progressTif2terrain(startLevel,out);
                            }catch (Exception e){
                                result.setCode(405);
                            }
                        }
                    }else{
                        changeProgress = 1d;
                    }
                    break;
                default:
                    changeProgress = 1d;
                    break;
            }
        }
        //logger.info("changeProgress={}",changeProgress);
        if(null != changeProgress && changeProgress == 1){
            redisTemplate.opsForValue().set(uuid + "ExchangeProgress",changeProgress,expiraTime,TimeUnit.HOURS);
        }
        map.put("exchangeProgress",null == changeProgress? null: changeProgress*100);
        //入库进度
        BigDecimal savedSize = BigDecimal.ZERO;
        BigDecimal progress = BigDecimal.ZERO;
        if(totalSize.compareTo(BigDecimal.ZERO)>0){
            String prefix = uuid+"SavedFile*";
            Set<String> keys = redisTemplate.keys(prefix);
            for(String key : keys){
                savedSize = savedSize.add(new BigDecimal(redisTemplate.opsForValue().get(key).toString()));
            }
            progress = savedSize.divide(totalSize,2,BigDecimal.ROUND_DOWN).multiply(new BigDecimal(100));
        }else{
            progress =  null!=redisTemplate.opsForValue().get(uuid + "SaveProgress")?new BigDecimal(redisTemplate.opsForValue().get(uuid + "SaveProgress").toString()):BigDecimal.ZERO;
        }
        map.put("saveProgress",progress);





        map.put("errorMsg",redisTemplate.opsForValue().get(uuid+"ErrorMsg"));
        //logger.info(uuid+"的unzipProgress={},saveProgress={},changeProgress={}",unzipProgress,progress,changeProgress);
        return result.success(map);
    }


    @PostMapping("selectSeverFile")
    @ApiOperation(value = "服务器文件选择", notes = "服务器文件选择")
    @ApiImplicitParams({
            @ApiImplicitParam(dataType = "String", name = "fileUrl", value = "路径", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "uuid", value = "上传位移标识", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "Integer", name = "serviceType", value = "服务类型", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "name", value = "服务名称", defaultValue = "0", required = true, paramType = "query"),
            @ApiImplicitParam(dataType = "String", name = "assinSuffixName", value = "后缀名", defaultValue = "0", required = true, paramType = "query")
    })
    public Result selectSeverFile(TabServiceVo vo) {
        Result result = new Result();
        //shp和tif不验证
        if(1!=vo.getServiceType() && 4!=vo.getServiceType()){
            String path = vo.getFileUrl();
            File file = new File(path);
            if(file.isFile() && 3!=vo.getServiceType()){
                path = path.substring(0, path.lastIndexOf(File.separator));
                if(6 == vo.getServiceType() && "pld".equals(vo.getChangeType())){
                    if(path.contains(".")){
                        return result.failure(-3, "文件路径不能含有 . 字符");
                    }
                }
            }
            //直接存库则需获取文件
//            if(vo.getServiceType() != 6 && vo.getServiceType() != 7 && vo.getServiceType() != 3 ){
//                Map<String,Object> map = FileList.recursionSelectFile(vo.getAssinSuffixName(),path,null,null);
//                result.setData(map);
//            }
//            if(null != map.get("errorMsg")){
//                return result.failure(-3, map.get("errorMsg").toString());
//            }

        }
        //注：选择的时候主动调用releaseTabService接口
        serviceUploadService.selectFileSave(vo,result);
        return result;
    }


}
